/*
 * OpenParts
 * A dynamic-loading components framework for GWT
 * Copyright (C) 2011 Christophe Bouthier  [chris{AT}binary-gastronome{DOT}fr]
 *
 * This work is partially based on work I have done at INRIA (http://www.inria.fr) 
 * in the context of the Qualipso European Project (http://qualipso.org/),
 * The work done at INRIA is Copyright (C) 2006-2011 INRIA
 *
 * This work is distributed under the LGPL version 3
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation. See the GNU
 * Lesser General Public License in LGPL.txt for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package fr.openparts.OpenParts.test.gwt.tests;

import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.ui.RootPanel;

import fr.openparts.OpenParts.client.OPBinding;
import fr.openparts.OpenParts.client.OPMessageFromEmbeddedViewHandler;
import fr.openparts.OpenParts.client.OPParams;
import fr.openparts.OpenParts.client.OPPartsLoader;
import fr.openparts.OpenParts.client.OPScheduler;
import fr.openparts.OpenParts.client.OPShell;
import fr.openparts.OpenParts.client.OPSlot;
import fr.openparts.OpenParts.test.gwt.dummyPart.client.DummyPart;

/**
 * GWT tests for the embedded view attachment handler.
 * 
 * @author Christophe Bouthier [chris{AT}binary-gastronome{DOT}fr]
 * @creation.date 02 May 2011
 */
public class OPOnEmbeddedViewAttachTestGwt extends GWTTestCase {

    private static final String SERVICE_NAME = "dummyService";
    private static final String RESOURCE_NAME = "dummyResource";
    private static final String ACTION_NAME = "dummyAction3";
    private static final String ACTION_NAME_2 = "dummyAction4";
    private static final String SLOT_ID = "slotId_onAttach";

    private DummyPart dummyPart;
    private OPSlot slot;

    private int slotHandlerCalls = 0;
    private int slotHandler2Calls = 0;

    /**
     * Return the name of the tested GWT Module.
     * 
     * @see com.google.gwt.junit.client.GWTTestCase#getModuleName()
     */
    @Override
    public final String getModuleName() {
        return "fr.openparts.OpenParts.test.gwt.TestOpenParts";
    }

    /**
     * Called at the start of each test to set up the part.
     * 
     * @see com.google.gwt.junit.client.GWTTestCase#gwtSetUp()
     */
    @Override
    protected void gwtSetUp() throws Exception {
        super.gwtSetUp();
        OPPartsLoader.bind();
        OPScheduler.bind();
        dummyPart = new DummyPart();
        dummyPart.bind();

        slot = OPShell.getSlot(SLOT_ID);
        slot.getViewProxy().addMessageHandler(new OPMessageFromEmbeddedViewHandler() {
            @Override
            public void handleMessageFromEmbeddedView(String message, OPParams params) {
            }
            @Override
            public void onEmbeddedViewAttach() {
                ++slotHandlerCalls;
            }
        });
    }

    /**
     * Called at the end of each test to clean up the mess.
     * 
     * @see com.google.gwt.junit.client.GWTTestCase#gwtTearDown()
     */
    @Override
    protected final void gwtTearDown() throws Exception {
        super.gwtTearDown();
        unbindOPPartsLoader(OPShell.opBindingSharedInstance());
        unbindOPScheduler(OPShell.opBindingSharedInstance());
        RootPanel.getBodyElement().removeChild(slot.getElement());
        slot = null;
        slotHandlerCalls = 0;
        slotHandler2Calls = 0;
    }

    /**
     * Test embedded view attachment handlers.
     */
    public final void testEmbeddedViewAttachHandlers() {
        RootPanel.getBodyElement().appendChild(slot.getElement());
        
        assertTrue("onEmbeddedViewAttach on view should not have been called yet", dummyPart.embeddedViewAttachHandlerCallsByIndex.isEmpty());
        assertEquals("onEmbeddedViewAttach on slot should not have been called yet", 0, slotHandlerCalls);
        
        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME, SLOT_ID);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("onEmbeddedViewAttach on view should have been called now", 1, dummyPart.embeddedViewAttachHandlerCallsByIndex.get(0).intValue());
        assertEquals("onEmbeddedViewAttach on slot should have been called now", 1, slotHandlerCalls);
    }

    /**
     * Test two embedded view attachment handlers.
     */
    public final void testEmbeddedViewAttachHandlersWithTwoHandlers() {
        slot.getViewProxy().addMessageHandler(new OPMessageFromEmbeddedViewHandler() {
            @Override
            public void handleMessageFromEmbeddedView(String message, OPParams params) {
            }
            @Override
            public void onEmbeddedViewAttach() {                
                ++slotHandler2Calls;
            }
        });
        
        RootPanel.getBodyElement().appendChild(slot.getElement());
          
        assertEquals("onEmbeddedViewAttach on view 1 should not have been called yet", 0, dummyPart.embeddedViewAttachHandler1Calls);
        assertEquals("onEmbeddedViewAttach on view 2 should not have been called yet", 0, dummyPart.embeddedViewAttachHandler2Calls);
        assertEquals("onEmbeddedViewAttach on slot 1 should not have been called yet", 0, slotHandlerCalls);
        assertEquals("onEmbeddedViewAttach on slot 2 should not have been called yet", 0, slotHandler2Calls);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2, SLOT_ID);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);
        
        assertEquals("onEmbeddedViewAttach on view 1 should have been called now", 1, dummyPart.embeddedViewAttachHandler1Calls);
        assertEquals("onEmbeddedViewAttach on view 2 should have been called now", 1, dummyPart.embeddedViewAttachHandler2Calls);
        assertEquals("onEmbeddedViewAttach on slot 1 should have been called now", 1, slotHandlerCalls);
        assertEquals("onEmbeddedViewAttach on slot 2 should have been called now", 1, slotHandler2Calls);
    }

    /**
     * Test attaching first then second view.
     */
    public final void testAttachFirstThenSecondView() {
        RootPanel.getBodyElement().appendChild(slot.getElement());
        final String SLOT_ID_2 = "slotId2";
        OPSlot slot2 = OPShell.getSlot(SLOT_ID_2);
        RootPanel.getBodyElement().appendChild(slot2.getElement());
        
        assertTrue("onEmbeddedViewAttach on view 1 and 2 should not have been called yet", dummyPart.embeddedViewAttachHandlerCallsByIndex.isEmpty());

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME, SLOT_ID);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("onEmbeddedViewAttach on view 1 should have been called now", 1, dummyPart.embeddedViewAttachHandlerCallsByIndex.get(0).intValue());
        assertEquals("onEmbeddedViewAttach on view 2 should still not have been called yet", 1, dummyPart.embeddedViewAttachHandlerCallsByIndex.size());

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME, SLOT_ID_2);

        assertEquals("onEmbeddedViewAttach on view 1 should have been called once", 1, dummyPart.embeddedViewAttachHandlerCallsByIndex.get(0).intValue());
        assertEquals("onEmbeddedViewAttach on view 2 should have been called now", 1, dummyPart.embeddedViewAttachHandlerCallsByIndex.get(1).intValue());
        
        RootPanel.getBodyElement().removeChild(slot2.getElement());
    }

    /**
     * Test attaching view to first then second slot.
     */
    public final void testAttachViewToFirstThenSecondSlot() {
        RootPanel.getBodyElement().appendChild(slot.getElement());
        final String SLOT_ID_2 = "slotId2_proxyMessages";
        final OPSlot slot2 = OPShell.getSlot(SLOT_ID_2);
        slot2.getViewProxy().addMessageHandler(new OPMessageFromEmbeddedViewHandler() {
            @Override
            public void handleMessageFromEmbeddedView(String message, OPParams params) {
            }
            @Override
            public void onEmbeddedViewAttach() {        
                ++slotHandler2Calls;
            }
        });
        RootPanel.getBodyElement().appendChild(slot2.getElement());
        
        assertEquals("onEmbeddedViewAttach on slot 1 should not have been called yet", 0, slotHandlerCalls);
        assertEquals("onEmbeddedViewAttach on slot 2 should not have been called yet", 0, slotHandler2Calls);
        
        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME, SLOT_ID);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);
        
        assertEquals("onEmbeddedViewAttach on slot 1 should have been called now", 1, slotHandlerCalls);
        assertEquals("onEmbeddedViewAttach on slot 2 should still not have been called yet", 0, slotHandler2Calls);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME, SLOT_ID_2);

        assertEquals("onEmbeddedViewAttach on slot 1 should have been called once", 1, slotHandlerCalls);
        assertEquals("onEmbeddedViewAttach on slot 2 should have been called now", 1, slotHandler2Calls);

        RootPanel.getBodyElement().removeChild(slot2.getElement());
    }

    /**
     * Unbind the OPScheduler.
     */
    private final native void unbindOPScheduler(final OPBinding opbinding) /*-{
        opbinding.scheduler = null;
    }-*/;

    /**
     * Unbind the OPPartsLoader.
     */
    private final native void unbindOPPartsLoader(final OPBinding binding) /*-{
        binding.partsLoader = null;
    }-*/;

    /**
     * Check if assertions are enabled.
     * 
     * @return true if assertions are enabled, false otherwise
     */
    private final boolean assertionsAreEnabled() {
        try {
            assert false;
            return false;
        } catch (AssertionError e) {
            return true;
        }
    }

}
